home *** CD-ROM | disk | FTP | other *** search
-
- ;$Author: DCODY $
- ;$Date: 07 Apr 1993 07:49:22 $
- ;$Header: X:/sccs/midi/midia.asv 1.9 07 Apr 1993 07:49:22 DCODY $
- ;$Log: X:/sccs/midi/midia.asv $
- ;
- ; Rev 1.9 07 Apr 1993 07:49:22 DCODY
- ; Silly! - I forgot to abort if the hardware was not detected!
- ;
- ; Rev 1.8 03 Feb 1993 12:03:04 DCODY
- ; changed an OR that should have been an AND. Changed a bunch of JLE to
- ; JB and one JLE that should have been an JB, which caused a buffer overrun.
- ;
- ; Rev 1.7 08 Dec 1992 16:51:22 DCODY
- ; moved externADDR macro for Borland Link. Also, added valid
- ; return codes for the init routine, which wasn't returning the
- ; correct value.
- ;
- ; Rev 1.6 23 Sep 1992 10:34:44 DCODY
- ; changed MVGetH... to mvGetH...
- ;
- ; Rev 1.5 04 Sep 1992 16:55:12 DCODY
- ; NEAR external choked large model programs
- ;
- ; Rev 1.4 20 Jul 1992 11:42:44 DCODY
- ; call to MVGetHWVersion requests active I/O detection. Found some
- ; I/O that was not relocatable, and now performs XOR relocation.
- ;
- ; Rev 1.3 17 Jul 1992 13:57:30 DCODY
- ; make I/O addresses relocatable.
- ;
- ; Rev 1.2 27 Jun 1992 15:44:56 DCODY
- ; removed debug output code.
- ;
- ; Rev 1.1 25 Jun 1992 21:48:46 DCODY
- ; PAS2 update
- ;
- ; Rev 1.0 15 Jun 1992 10:42:58 BCRANE
- ; Initial revision.
- ;$Logfile: X:/sccs/midi/midia.asv $
- ;$Modtimes$
- ;$Revision: 1.9 $
- ;$Workfile: midia.asm $
-
- Title MIDIA.ASM -- Media Vision 3802 Midi Hardware Dependent Module
- Subttl Copyright (c) 1991,1992. Media Vision Inc. All Rights Reserved.
- page 64,131
-
- ; /*\
- ;---|*|-----------------------====< MIDIA.ASM >====------------------------
- ;---|*|
- ;---|*| Low Level MIDI I/O routines for the Pro Audio Spectrum cards.
- ;---|*|
- ; \*/
-
- .xlist
- include model.inc
- include masm.inc
- include mvmidi.inc
- include common.inc
- include target.inc
- .list
-
- ;
- ; /*\
- ;---|*|----====< int mvMIDIEnable >====----
- ;---|*|
- ;---|*| mvMIDIEnable - Initialize the MIDI interface
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| wParm1 is a bit field for process control
- ;---|*| D0 = 1 to enable input interrupts
- ;---|*| D1 = 1 to enable output interrupts
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = -1 if cannot init the MIDI hardware.
- ;---|*|
- ;---|*|----====< void mvMIDIDisable >====----
- ;---|*|
- ;---|*| mxdDisable - MIDI shutdown
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| There is no return value.
- ;---|*|
- ;---|*|----====< int mvMIDIGetBuff >====----
- ;---|*|
- ;---|*| mvMIDIGetBuff - get data byte from MIDI channel
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 holds the count to move
- ;---|*| dParm2 points to the target buffer
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| AX = 0, no data, # of bytes moved
- ;---|*|
- ;---|*|----====< int mvMIDIGetByte >====----
- ;---|*|
- ;---|*| mvMIDIGetByte - get/check one byte from MIDI channel buffer
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| None
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| AX = byte, or -1 if no data
- ;---|*|
- ;---|*|----====< void mvMIDISendBuff >====----
- ;---|*|
- ;---|*| mvMIDISendBuff - send a buffer of data
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 = integer of count to load
- ;---|*| dParm1 = far pointer to the buffer
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| There is no return value.
- ;---|*|
- ;---|*|----====< void mvMIDISendByte >====----
- ;---|*|
- ;---|*| mvMIDISendByte - send data byte out MIDI channel
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 datum
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| There is no return value.
- ;---|*|
- ; \*/
- ;
-
- externADDR mvGetHWVersion ; determine the installed hardware type
-
- .data
- ;
- ; /*\
- ;---|*|------------====< Global Data Definitions >====------------
- ; \*/
- ;
- extrn _MVTranslateCode:word
- extrn _MVHWVersionBits:word
- ;
- ; The overflow count will always be here, but we won't make it public
- ; except for debugging purposes
- ;
-
- ifdef DEBUG
- public _overflow
- endif
- _overflow dw 0 ; overflow count
-
- ;
- ; MidiInFilter allows certain types of MIDI messages to be tossed out...
- ;
- ; NOTE: this currently works for active sense ONLY.
- ;
- public _MidiInFilter
- _MidiInFilter dw MF_ACTSENSE ; default ignores active sense
-
- ;
- ; /*\
- ;---|*|------------====< Private Data Definitions >====------------
- ; \*/
- ;
-
- ;
- ; This midi code uses interrupt driven I/O, so a circular buffer is used
- ; to support the data flow.
- ;
-
- MAXQUEUE equ 128
-
- ;
- ; MIDI input circular buffer
- ;
- iCircularQueue db MAXQUEUE dup (0)
-
- MIDIiQueueCnt dw 0
-
- lpiMIQueue dw iCircularQueue
- lpiMOQueue dw iCircularQueue
-
- ;
- ; MIDI output circular buffer
- ;
- oCircularQueue db MAXQUEUE dup (0)
-
- MIDIoQueueCnt dw 0
-
- lpoMIQueue dw oCircularQueue
- lpoMOQueue dw oCircularQueue
-
- ;
- ; Interrupt channel number and mask
- ;
-
- _IRQNumb db -1
- _IRQMask db 0
-
- ;
- ; Interrupt Service Routine re-entrancy sema-phore
- ;
- ISRbusy db -1 ; ISR semaphore
-
- ;
- ; Internal process control to handle polled or interrupt driven data I/O
- ;
- ProcessControl db 0 ; Interrupt or polled I/O
- INTINPUT equ 00000001b
- INTOUTPUT equ 00000010b ; (currently not implemented)
-
-
- ;
- ; /*\
- ;---|*|------------====< Yamaha 3802 midi interface variables >====------------
- ; \*/
- ;
-
- MDctrl db 0 ; MDSYSCTLR shadow for write only hardware
- ISRenab db 0 ; R06 TX and RX int enable bits
-
- ; r02/r03/r06 bit definitions
- TxIRQ equ 01000000b ; Tx FIFO interrupt
- RxIRQ equ 00100000b ; Rx FIFO interrupt
-
- ; r34 bit definitions
- RxRDY equ 10000000b ; Rx FIFO non-empty
-
- ; r54 bit definitions
- TxEMP equ 10000000b ; Tx FIFO empty
- TxRDY equ 01000000b ; Tx FIFO non-full
-
- TIMER1 equ 2173
-
- ;
- ;------------------------================================----------------------
- ;------------------------====< MIDI Common Routines >====----------------------
- ;------------------------================================----------------------
- ;
- .code
- assume ds:@data,es:nothing
-
- ;
- ; We will save the old IRQ vector here to guarrantee access at all times.
- ;
-
- OldISR dd 0 ; holds the original IRQ vector
-
- ;
- ; Toggle the MIDI interrupt to stimulate latent IRQs
- ;
- ToggleMV101mask macro
-
- mov dx,INTRCTLR
- xor dx,[_MVTranslateCode]
-
- in al,dx
- xor al,bICmidi ; disable MIDI interrupts
- out dx,al
- pause
- xor al,bICmidi ; enable MIDI interrupts
- out dx,al
-
- endm
-
- ;
- ; /*\
- ;---|*|----====< int mvMIDIEnable >====----
- ;---|*|
- ;---|*| Initialize the MIDI interface
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| wParm1 is a bit field for process control:
- ;---|*| D0 = 1 to enable input interrupts.
- ;---|*| D1 = 1 to enable output interrupts.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX = -1 if cannot init the MIDI hardware.
- ;---|*|
- ; \*/
- ;
- public mvMIDIEnable
- mvMIDIEnable proc
- push bp ; frame the stack for our 1 parameter
- mov bp,sp
- ;
- ; reset the MIDI buffering system
- ;
- mov [lpiMIQueue],OFFSET iCircularQueue
- mov [lpiMOQueue],OFFSET iCircularQueue
- mov [lpoMIQueue],OFFSET oCircularQueue
- mov [lpoMOQueue],OFFSET oCircularQueue
- mov [MIDIoQueueCnt],0
- mov [MIDIiQueueCnt],0
- mov [_overflow],0
- mov [_MidiInFilter],MF_ACTSENSE
- ;
- ; If the hardware bits have not been determined, do it...
- ;
- cmp _MVHWVersionBits,-1 ; version bits = -1 if the function
- jnz @F ; hasn't been called yet.
- mov ax,USE_ACTIVE_ADDR ; do the call
- push ax ; to setup the hardware bits, etc.
- call mvGetHWVersion
-
- cmp ax,-1 ; is the hardware installed?
- pop ax
- jz mvmienbad ; no, exit bad...
-
- ;
- @@:
- ;
- ; determine the IRQ for the Pro Audio card
- ;
- call whereirq ; looks for MVSOUND.SYS
- ;
- ; convert each bit to a full mask. Send this mask to each routine.
- ;
- mov ax,wParm1 ; load the bit flags
- mov [ProcessControl],al ; save as our process control
- ror ax,1 ; ah holds input bit, al holds output
- neg ah
- sbb ah,ah ; ah = FF to enable ints, else 0
- neg al
- sbb al,al ; al = FF to enable ints, else 0
- ;
- ; perform the proper init
- ;
- test [_MVHWVersionBits],bMV101; MV101 version of MIDI?
- jz @F ; no, go do yamaha
- ;
- ; initialize the MV101 MIDI device
- ;
- call enable_mv101
- jc mvmienbad ; cannot set it up...
- sub ax,ax ; return oky doky...
- pop bp
- ret
- ;
- @@:
- ;
- ; initialize the Yamaha 3802
- ;
- call enable_yamaha
- jc mvmienbad ; cannot set it up...
- sub ax,ax ; return oky doky...
- pop bp
- ret
- ;
- mvmienbad:
- mov ax,-1 ; exit bad...
- pop bp
- ret
-
- mvMIDIEnable endp
-
- ;
- ; /*\
- ;---|*|----====< void mvMIDIDisable >====----
- ;---|*|
- ;---|*| MIDI device shutdown.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| There is no return value.
- ;---|*|
- ; \*/
- ;
- public mvMIDIDisable
- mvMIDIDisable proc
- ;
- ; remove ourselves from the chain
- ;
- call unhook_interrupt
- ;
- ; perform the proper init
- ;
- test [_MVHWVersionBits],bMV101; MV101 version of MIDI?
- jz @F ; no, go do yamaha
-
- call disable_MV101 ; disable the MV101 MIDI
- ret
- ;
- @@:
- call disable_yamaha ; disable the Yamaha MIDI
- ;
- midblexit:
- ret
-
- mvMIDIDisable endp
-
- ;
- ; /*\
- ;---|*|----====< int mvMIDIGetBuff >====----
- ;---|*|
- ;---|*| Get data byte from MIDI channel.
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 holds the count to move.
- ;---|*| dParm2 points to the target buffer.
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| AX = 0, no data, # of bytes moved.
- ;---|*|
- ; \*/
- ;
- public mvMIDIGetBuff
- mvMIDIGetBuff proc
- push bp
- mov bp,sp
- ;
- ; save the C criticals
- ;
- push es
- push si
- push di
- ;
- ; load the parameters
- ;
- mov cx,wParm1 ; get the number of bytes to move
- les di,wParm2 ; get the target pointer
- mov si,[lpiMOqueue] ; get the source pointer
- sub dx,dx ; dx holds the # of bytes moved
- cld
- ;
- ; using interrupt driven input?
- ;
- test [ProcessControl],INTINPUT
- jz mvigb_20 ; polled, check each h/w
- ;
- mvigb_05:
- ;
- ; read as many bytes out of the queues until one is empty, or full.
- ;
- cmp [MIDIiQueueCnt],0 ; all done?
- jz mvigb_10 ; yes, return # of bytes moved
- movsb
- dec [MIDIiQueueCnt] ; one less byte here...
- inc dx
- cmp si,offset iCircularQueue+MAXQUEUE
- jb @F
- mov si,offset iCircularQueue
- ;
- @@:
- loop mvigb_05 ; get it all...
- ;
- mvigb_10:
- mov [lpiMOQueue],si ; save the pointer
- mov ax,dx
- ;
- mvigb_ret:
- pop di
- pop si
- pop es
- pop bp
- ret
- ;
- mvigb_20:
- ;
- ; This is a little slow, but avoids messy code duplication
- ;
- push si ; save si
- mov si,cx ; si will be our loop counter
- mov bp,cx ; bp will hold the total count
- ;
- mvigb_25:
- call FFAR ptr mvMIDIGetByte ; get the next byte
- cmp ax,-1 ; any data?
- jz mvigb_30 ; nope, we're done...
- stosb ; save in the callers buffer
- dec si ; all done?
- jnz mvigb_25 ; nope, continue looping
- ;
- mvigb_30:
- sub bp,si ; bp holds the total read count
- mov ax,bp
- pop si
- jmp short mvigb_ret
-
- mvMIDIGetBuff endp
-
- ;
- ; /*\
- ;---|*|----====< int mvMIDIGetByte >====----
- ;---|*|
- ;---|*| Get one byte from MIDI channel buffer.
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| AX = -1 if no data.
- ;---|*| AH = 0 if data in AL.
- ;---|*|
- ; \*/
- ;
- public mvMIDIGetByte
- mvMIDIGetByte proc
- ;
- ; If the code is running as interrupt input, then we can check the queue
- ;
- test [ProcessControl],INTINPUT
- jz mvgbt_20 ; polled, check each h/w
-
- cmp [MIDIiQueueCnt],0 ; any data?
- jz mvgbt_none ; no, just return now
-
- mov bx,[lpiMOqueue] ; get the source pointer
- sub ah,ah ; clear out the top
- mov al,[bx] ; load the bottom
-
- dec [MIDIiQueueCnt] ; one less byte here...
- inc bx
- cmp bx,offset iCircularQueue+MAXQUEUE
- jb mvgbt_05
- mov bx,offset iCircularQueue
- ;
- mvgbt_05:
- mov [lpiMOqueue],bx ; save the new pointer
- ret
- ;
- mvgbt_none:
- mov ax,-1 ; bad, so exit with error flag
- ret
- ;
- mvgbt_20:
- ;
- ; This is the polled mode of MIDI input - go check the correct chip FIFO
- ;
- test [_MVHWVersionBits],bMV101; MV101 version of MIDI?
- jz mvgbt_yamaha ; no, go do yamaha
- ;
- ; read the MV101 MIDI fifo
- ;
- mov dx,MIDISTATUS ; check data available
- xor dx,[_MVTranslateCode] ; translated I/O addr
-
- in al,dx ; isolate the data available bit
- and ax,bMSRififo
- jz mvgbt_none ; no data available, go report it...
-
- mov dx,MIDIDATA
- xor dx,[_MVTranslateCode] ; translated I/O addr
-
- in al,dx ; return the byte in al, ah = 0
-
- ret
- ;
- mvgbt_yamaha:
- ;
- ; read the Yamaha 3802 MIDI fifo.
- ;
- mov al, 3 ; 3x
- mov dx, MDSYSCTLR ; set the 3802 global reg set index
- mov [MDctrl],al ; shadow...
- out dx, al
-
- mov dx, MDGROUP4 ; 34 = FIFO-Rx status
- in al, dx
- and ax, RxRDY ; RxRDY bit?
- jz mvgbt_none ; no data available, go report it...
-
- mov dx, MDGROUP6 ; 36 = FIFO-Rx data
-
- in al, dx ; return the byte in al, ah = 0
-
- ret
-
- mvMIDIGetByte endp
-
- ;
- ; /*\
- ;---|*|----====< void mvMIDISendByte >====----
- ;---|*|
- ;---|*| mvMIDISendByte - send a MIDI data byte out the MIDI channel.
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 - MIDI byte to be sent.
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| There is no return value.
- ; \*/
- ;
- public mvMIDISendByte
- mvMIDISendByte proc
- ;
- ; send the byte out directly if polled output, else queue it up to keep order
- ;
- push bp
- mov bp,sp
-
- mov al,wParm1 ; grab the byte
-
- test [ProcessControl],INTOUTPUT ; interrupt output?
- jnz mvsnd_ints ; yes, we will queue it...
-
- call dosendbyte ; send it out straight
-
- pop bp
- ret
- ;
- mvsnd_ints:
- ;
- ; Interrupt driven output requires the byte be queue to keep the byte order.
- ;
- mov bx,[lpoMIQueue] ; get the input-to-buffer pointer
- ;
- @@:
- cmp [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
- jnz @F ; no, go load another byte
- call primexmit ; make sure the xmitter is working
- jmp short @B ; go wait for data to move
- ;
- @@:
- mov [bx],al
- inc bx
- cmp bx,offset oCircularQueue+MAXQUEUE ; wrapped?
- jb @F
- mov bx,offset oCircularQueue ; yes, go back to the beginning
- ;
- @@:
- mov [lpoMIQueue],bx ; save the new input-to-buffer pointer
- inc [MIDIoQueueCnt] ; add one more into the FIFO
-
- call primexmit ; make sure the xmitter is working
- pop bp
- ret
-
- mvMIDISendByte endp
-
- ;
- ; /*\
- ;---|*|----====< void mvMIDISendBuff >====----
- ;---|*|
- ;---|*| mvMIDISendBuff - send a buffer of data.
- ;---|*|
- ;---|*| Entry Conditions
- ;---|*| wParm1 = integer of count to load.
- ;---|*| dParm1 = far pointer to the buffer.
- ;---|*|
- ;---|*| Exit Conditions
- ;---|*| Returns when all the bytes are loaded in the circular queue.
- ; \*/
- ;
- public mvMIDISendBuff
- mvMIDISendBuff proc
- push bp
- mov bp,sp ; 'C' frame
-
- push es ; save the 'C' criticals
- push si
- ;
- ; we will load the entire block into the FIFO. This even means waiting for the
- ; transmitter to empty enough data until we're done.
- ;
- mov cx,wParm1 ; get the buffer counter
- les si,wParm2 ; get the far pointer
- mov bx,[lpoMIQueue] ; get the input-to-buffer pointer
- ;
- queueloop:
- cmp [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
- jnz @F ; no, go load another byte
- call primexmit ; make sure the xmitter is working
- jmp short queueloop
- ;
- @@:
- lods byte ptr es:[si] ; get the next MIDI byte
- mov [bx],al
- inc bx
- cmp bx,offset oCircularQueue+MAXQUEUE ; wrapped?
- jb @F
- mov bx,offset oCircularQueue ; yes, go back to the beginning
- ;
- @@:
- inc [MIDIoQueueCnt] ; add one more into the FIFO
- loop queueloop ; load all the bytes into the queue
- mov [lpoMIQueue],bx ; save the new input-to-buffer pointer
- ;
- ; We've loaded the FIFO. if polling, call the output routine till done.
- ;
- test [ProcessControl],INTOUTPUT ; interrupt driven output?
- jnz sendbuffints ; yes, force the xmitter to work
- ;
- ; this byte goes out the MV101
- ;
- @@:
- call primexmit ; make sure the xmitter is working
- cmp [MIDIoQueueCnt],0 ; any more queued up data?
- jnz @B ; yes, stay here till sent...
-
- jmp short sendbuffexit ; all done, return home
- ;
- sendbuffints:
- ;
- ; make sure the xmitter is primed to generate interrupts
- ;
- call primexmit
- ;
- sendbuffexit:
- pop si
- pop es
- pop bp
- ret
-
- mvMIDISendBuff endp
-
- ;
- ;---------------------------==============================---------------------
- ;---------------------------====< Local Subroutines > ====---------------------
- ;---------------------------==============================---------------------
- ;
-
- ;
- ; /*\
- ;---|*|----====< disable_MV101 >====----
- ;---|*|
- ;---|*| This routine will disable any MV101 MIDI
- ;---|*| interrupts and reset the tranceiver.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX, DX modified
- ;---|*|
- ; \*/
- ;
- disable_MV101 proc near
-
- mov dx,MIDICONTROL ; get the control address
- xor dx,[_MVTranslateCode] ; translate the address
-
- sub al,al ; flush all enables
- out dx,al ; kill fifo irq
-
- ret
-
- disable_MV101 endp
-
- ;
- ; /*\
- ;---|*|----====< disable_yamaha >====----
- ;---|*|
- ;---|*| This routine will disable any Yamaha MIDI
- ;---|*| interrupts and reset the tranceiver.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX, DX modified
- ;---|*|
- ; \*/
- ;
- disable_yamaha proc near
- ;
- ; disable interrupts in the yamaha 3802
- ;
- sub ax, ax
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 0x
-
- mov dx, MDGROUP6 ; 06 = IRQ enable request
- out dx, al
-
- .errnz MDGROUP6-MDGROUP5-1
-
- dec dx ; 05 = IRQ mode control
- out dx, al
-
- ret
-
- disable_yamaha endp
-
- ;
- ; /*\
- ;---|*|----====< dosendbyte >====----
- ;---|*|
- ;---|*| A generic routine to send one byte out to the hardware.
- ;---|*|
- ;---|*| Entry Conditions;
- ;---|*| AL holds the byte to be sent.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX modified.
- ;---|*| Byte sent, no return value.
- ;---|*|
- ; \*/
- ;
- dosendbyte proc near
- ;
- ; save the byte until we need it...
- ;
- mov ah,al ; ah holds the byte to send
- ;
- ; select the proper chip.
- ;
- test [_MVHWVersionBits],bMV101; MV101 version of MIDI?
- jz send_yamaha ; no, go do yamaha
- ;
- ; this byte goes out the MV101
- ;
- mov dx, MIDIFIFOS ; get the transmitter status
- xor dx,[_MVTranslateCode] ; translated I/O addr
- ;
- ; we will only load up to 15 bytes in the output FIFO since a zero count
- ; means either 16 bytes free or 0 bytes free. By only loading 15 bytes max,
- ; we assume a zero means 16 bytes free.
- ;
- in al,dx ; get the FIFO output free room count
- and al,bMFCofifo ; isolate the count
- jz mvsendit ; 16 bytes free
- sub cx,cx ; we will do a timeout
- ;
- @@:
- in al, dx ; get the FIFO counts
- and al, bMFCofifo ; any room in the output FIFO?
- cmp al, 10h ; one byte left in the FIFO?
- loopz @b ; wait till there is more room
- jcxz deadtx ; exit on a timeout
- ;
- mvsendit:
- mov dx, MIDIDATA ; get the data output port
- xor dx,[_MVTranslateCode] ; translated I/O addr
-
- mov al, ah
- out dx, al ; ship stuff...
- ;
- deadtx:
- ret
- ;
- send_yamaha:
- ;
- ; this byte goes out the yamaha 3802
- ;
- mov al, 5 ; 5x
- mov [MDctrl], al ; shadow it...
- mov dx, MDSYSCTLR ; get the port
- out dx, al ; let'er rip...
-
- mov dx, MDGROUP4 ; 54 = FIFO-Tx status
- ;
- @@: in al, dx
- test al, TxRDY ; TxRDY bit?
- jz @b ; ..jump if FIFO full
-
- mov dl, LOW MDGROUP6 ; 56 = FIFO-Tx data
- mov al, ah
- out dx, al ; ship datum
-
- ret
-
- dosendbyte endp
-
- ;
- ; /*\
- ;---|*|----====< enable_mv101 >====----
- ;---|*|
- ;---|*| Enable the MV101 tranceiver, and any appropriate interrupts
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| AH = FF to enable input interrupts
- ;---|*| AL = FF to enable output interrupts
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX modified.
- ;---|*| Carry clear -- assumed to be good
- ;---|*|
- ; \*/
- ;
- enable_mv101 proc near
- ;
- ; build the correct mask bits in ah
- ;
- and ax,(bMCRenafifoi SHL 8) + bMCRenafifoo
- or ah,al ; ah holds the enable bits
- ;
- ; do something to the test register
- ;
- ;;; mov dx,MIDITEST
- ;;; xor dx,[_MVTranslateCode] ; translated I/O addr
- ;;; mov al,0FFh
- ;;; out dx,al
- ;
- ; setup the MIDI prescale
- ;
- mov dx,MIDIPRESCALE
- xor dx,[_MVTranslateCode] ; translated I/O addr
- mov al,10h ;
- out dx,al
- ;
- ; reset the fifos
- ;
- mov dx,MIDICONTROL
- xor dx,[_MVTranslateCode] ; translated I/O addr
- mov al,bMCRrstfifoi+bMCRrstfifoo
- out dx,al ; send the reset bits
- mov al,ah
- out dx,al ; clear reset bits and set enables
- ;
- ; reset any present status bits
- ;
- mov dx,MIDISTATUS
- xor dx,[_MVTranslateCode] ; translated I/O addr
- mov al,-1 ; reset all midi status bits
- out dx,al
- ;
- ; only enable the stuff if we're using interrupts
- ;
- test [ProcessControl],INTINPUT+INTOUTPUT
- jz enamv_done ; no interrupts, just exit now...
- ;
- ; install the interrupt handling now
- ;
- cli
-
- lea ax,MV101_ISR
- call hook_interrupt ; insert our routine
-
- sti
- ;
- enamv_done:
- clc
- ret
-
- enable_mv101 endp
-
- ;
- ; /*\
- ;---|*|----====< enable_yamaha >====----
- ;---|*|
- ;---|*| Enable the Yamaha 3802 tranceiver, and any appropriate interrupts.
- ;---|*|
- ;---|*| Enable the 3802 Yamaha MIDI device
- ;---|*| AH = FF to enable input interrupts.
- ;---|*| AL = FF to enable output interrupts.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX modified.
- ;---|*| Carry clear -- assumed to be good
- ;---|*|
- ; \*/
- ;
- enable_yamaha proc near
- ;
- ; build the correct mask bits in ah
- ;
- and ax,(RxIRQ SHL 8)+ TxIRQ
- or al,ah ; al holds the enable bits
- push ax ; save the interrupt enable bits
- ;
- ; reset the 3802 midi chip
- ;
- mov al, 80h ; master clear
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al
-
- mov cx, 100
- @@: in al, dx ; wait 32 TCLK
- loop @b
-
- xchg ax,cx ; load zero
- out dx,al ; flush the reset bit
-
- mov al, 6
- mov [MDctrl], al
- out dx, al ; 6x
- mov dx, MDGROUP6 ; 66 = Click counter control
- mov al, 00000010b ; Clock=1.0MHz, no click pulse
- out dx, al
-
- mov al, 4
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 4x
- mov dx, MDGROUP4 ; 44 = Tx communication rate
- mov al, 00001000b ; CLKM/32 = 31,250 bps
- out dx, al
-
- mov al, 2
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 2x
- mov dx, MDGROUP4 ; 24 = Rx communication rate
- mov al, 00001000b ; CLKM/32 = 31,250 bps
- out dx, al
-
- mov al, 5
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 5x
- mov dx, MDGROUP5 ; 55 = FIFO-Tx control
- mov al, 10000101b ; TxE
- out dx, al
-
- mov al, 8
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 8x
- mov dx, MDGROUP4 ; 84 = General Timer LSB
- mov ax, TIMER1
- out dx, al
- mov dx, MDGROUP5 ; 85 = General Timer MSB
- xchg ah, al
- out dx, al
- ;
- ; clear the FIFO-Rx
- ;
- mov al, 3 ; 35 = RCR: FIFO-Rx control
- mov [MDctrl], al ; bit 7 = clear FIFO-Rx
- mov dx, MDSYSCTLR ; bit 6 = clear RxOV flag
- out dx, al ; bit 4 = enable MIDI-clock filter
- mov dx, MDGROUP5 ; bit 3 = clear BRK flag
- mov al, 11001101b ; bit 2 = clear RxOL flag
- out dx, al ; bit 1 = enable Address-hunter
- ;
- ; only enable the stuff if we're using interrupts
- ;
- test [ProcessControl],INTINPUT+INTOUTPUT
- jz enayam_already ; no interrupts, just exit now...
- ; ; bit 0 = enable Receiver
- ; initialize the 3802 chip IRQ system
- ;
- sub al, al
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 0x
- mov dx, MDGROUP5 ; 05 = IRQ mode control
- mov al, 0011b ; VE+VM
- out dx, al
- ;
- ; initialize the board and motherboard IRQ systems
- ;
- cli
-
- .errnz MDGROUP6-MDGROUP5-1
- inc dx
-
- pop ax ; get the interrupt enable bits
- out dx, al
- mov [ISRenab], al
-
- mov dx, MDGROUP4 ; flush any pending IRQs
- mov al, 0ffh
- out dx,al
- ;
- ; hook the actual vector
- ;
- lea ax,Yamaha_ISR
- call hook_interrupt
- sti
-
- clc
- ret
- ;
- enayam_already:
- pop ax
- clc
- ret
-
- enable_yamaha endp
-
- ;
- ; /*\
- ;---|*|----====< hook_interrupt >====----
- ;---|*|
- ;---|*| Hook the Pro Audio hardware interrupt,
- ;---|*| and enable the system interrupt.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX modified.
- ;---|*|
- ; \*/
- ;
- hook_interrupt proc near
- push ds
- push es
-
- cmp wptr cs:[OldISR+2],0 ; any segment?
- jnz midihooked ; yes, we've hooked already
-
- push ax ; save the IRQ offset
-
- mov ax, 3508h ; DOS : get vector
- cmp [_IRQNumb],7 ; 1st IRQ channel?
- jbe @F
- mov al,70h-8 ; 2nd IRQs start at 70H
- ;
- @@:
- add al, [_IRQNumb] ; IRQ
- push ax ; save the IRQ #
-
- int 21h ; fetch the vector
-
- mov wptr cs:[OldISR+0], bx ; save original value
- mov wptr cs:[OldISR+2], es
-
- pop ax
- pop dx ; get the actual offset
-
- push ds ; save ds over the int call
- push cs
- pop ds ; ds:dx point to the vector
- mov ah, 25h ; DOS : set vector
- int 21h
- pop ds
- ;
- ; enable the Pro Audio IRQ channel
- ;
- pushf
- cli
- ;
- ; address the correct IRQ controller
- ;
- mov dx,IRQ1MASKREG
- cmp [_IRQNumb],7 ; 1st IRQ controller?
- jbe @F ; yes, continue on...
- mov dx,IRQ2MASKREG ; no, use the 2nd interrupt
- ;
- @@:
- ;
- ; Enable the correct IRQ channel
- ;
- in al, dx ; enable the system IRQ
- mov ah, [_IRQMask]
- not ah
- and al, ah
- out dx, al
- ;
- ; Enable the Pro Audio MIDI interrupt
- ;
- mov dx, INTRCTLR ; Enable the PAS. This could signal
- xor dx, [_MVTranslateCode]
- in al, dx ; an interrupt immediately.
- or al, bICmidi ; MIDI interrupt enable
- out dx, al
-
- popf
- ;
- midihooked:
-
- pop es
- pop ds
- ret
-
- hook_interrupt endp
-
- ;
- ; /*\
- ;---|*|----====< void primexmit >====----
- ;---|*|
- ;---|*| Prime the transmitter. If interrupt driven output, make sure the
- ;---|*| outbound FIFO has at least one byte loaded. If polled, send
- ;---|*| the next polled byte.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| Working registers assumed to hold data.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| No registers modified.
- ;---|*|
- ; \*/
- ;
- primexmit proc near
- ;
- ; save everything for the caller
- ;
- pushf ; save the flags so we can CLI
- push ax ; don't mess with any other registers
- push dx
- push bx
- push cx
- ;
- ; Interrupt driven output is a special case. We just have to prime the pump...
- ;
- test [ProcessControl],INTOUTPUT ; interrupt driven output?
- jnz prixmints ; yes, force the xmitter to work
- ;
- prixprimeit:
- ;
- ; This is polled output mode. We just send one byte out. The caller will keep
- ; calling us till the queue is emptied.
- ;
- cmp [MIDIoQueueCnt],0 ; any data to send?
- jz prixdone ; no, it's all loaded and gone..
-
- mov bx,[lpoMOQueue] ; get the out-of-buffer pointer
- mov al,[bx]
- inc bx
-
- cmp bx,offset oCircularQueue+MAXQUEUE ; wrapped?
- jb @F
- mov bx,offset oCircularQueue ; yes, wrap it...
- ;
- @@:
- mov [lpoMOQueue],bx ; save the new input-to-buffer pointer
- dec [MIDIoQueueCnt] ; add one more into the FIFO
-
- call dosendbyte ; send it via the polled routines
- ;
- prixdone:
- ;
- ; return with nothing changed
- ;
- pop cx
- pop bx
- pop dx
- pop ax
- popf
- ret
- ;
- prixmints:
- ;
- ; in case of some MIDI interrupts occuring when we don't expect it, (such
- ; as MIDI in interrupts) this section will be executed without interrupts
- ; to avoid double sending, or sending data from the queue out of order.
- ;
- cli ; no ints while we go to prime the pump
- ;
- ; Make sure the transmitter FIFO has data loaded. This guarrantees an interrupt
- ; when the FIFO is empty.
- ;
- test [_MVHWVersionBits],bMV101; MV101 version of MIDI?
- jz prixyamaha ; no, go do yamaha
-
- mov dx, MIDIFIFOS ; get the transmitter FIFO status
- xor dx,[_MVTranslateCode] ; translated I/O addr
-
- in al,dx ; get the FIFO output free room count
- and al,bMFCofifo ; isolate the outbound count
- jnz prixdone ; there is data, no need to prime it.
- jmp short prixprimeit ; 16 bytes free - load one more...
- ;
- prixyamaha:
- ;
- ; Yamaha 3802 - we go to TX register set 05 to find the TX empty bit
- ;
- mov al, 5 ; reg set 5x is for the xmitter
- mov [MDctrl], al
- mov dx, MDSYSCTLR
- out dx, al ; 5x
-
- mov dx, MDGROUP4 ; 84 = General Timer LSB
- in al,dx
- test al,TxEMP ; is the transmitter empty?
- jnz prixprimeit ; yes, go load another byte
- jmp short prixdone ; no, leave it alone
-
- primexmit endp
-
- ;
- ; /*\
- ;---|*|----====< unhook_interrupt >====----
- ;---|*|
- ;---|*| If installed, disable the IRQ system, then unhook
- ;---|*| the Pro Audio IRQ handler from the chain.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX may be modified.
- ;---|*|
- ; \*/
- ;
- unhook_interrupt proc near
- ;
- ; don't do this if there is no need
- ;
- cmp wptr cs:[OldISR+2],0 ; interrupt already unhooked?
- jz unhooked ; yes, just exit
- ;
- ; disable system interrupt for the Pro Audio card
- ;
- pushf
- cli
-
- test al,fICintmaskbits ; any other interrupts enabled
- jnz mskint_done ; yes, leave the system mask alone
-
- mov dx,IRQ1MASKREG
- cmp [_IRQNumb],7 ; 1st IRQ controller?
- jbe @F ; yes, continue on...
- mov dx,IRQ2MASKREG ; no, use the 2nd interrupt
- ;
- @@:
- cmp [_IRQNumb],2 ; hardware IRQ 2?
- jz mskint_done ; yes, never mask it
-
- in al,dx
- or al,[_IRQMask] ; no, kill the system interrupts
- out dx,al
- ;
- mskint_done:
- mov dx, INTRCTLR ; disable the Pro Audio MIDI IRQ
- xor dx, [_MVTranslateCode]
- in al, dx
- and al, not bICmidi ; MIDI interrupt disable
- out dx, al
-
- popf
- ;
- ; calculate the correct vector and restore it.
- ;
- mov ax, 2508h ; DOS : set vector
- cmp [_IRQNumb],7 ; 1st IRQ channel?
- jbe @F
- mov al,70h-8 ; 2nd IRQs start at 70H
- ;
- @@:
- add al, [_IRQNumb] ; IRQ
- ;
- ; do it through DOS...
- ;
- push ds
- lds dx, cs:[OldISR]
- int 21h
- pop ds
-
- mov wptr cs:[OldISR+2],0 ; flush the segment of the vector
- ;
- unhooked:
- ret
-
- unhook_interrupt endp
-
- ;
- ; /*\
- ;---|*|----====< whereirq >====----
- ;---|*|
- ;---|*| This routine queries MVSOUND.SYS for the Pro Audio IRQ. Once
- ;---|*| determined, then an appropriate interrupt mask will be
- ;---|*| generated, and saved for future reference.
- ;---|*|
- ;---|*| Entry Conditions:
- ;---|*| None.
- ;---|*|
- ;---|*| Exit Conditions:
- ;---|*| AX,BX,CX,DX may be modified.
- ;---|*|
- ; \*/
- ;
- whereirq proc near
- ;
- ; Do this just once
- ;
- cmp [_IRQNumb],-1 ; have we been through here?
- jnz IRQdone ; yes, it's been found
- ;
- ; Call MVSOUND.SYS to get the DMA/IRQ
- ;
- mov ax,0bc04h ; call MVSOUND.SYS for it...
- int 2fh
- ;
- ; register the IRQ if the call was good
- ;
- cmp ax,'MV' ; was this a good call?
- jnz IRQdone
-
- mov [_IRQNumb],cl ; save the #
- mov ax,1
- shl ax,cl
- or al,ah
- mov [_IRQMask],al ; save the mask.
- ;
- IRQdone:
- ret
-
- whereirq endp
-
- ;
- ;------------------------===================================-------------------
- ;------------------------====< MIDI Interrupt Service > ====-------------------
- ;------------------------===================================-------------------
- ;
-
- ;
- ; /*\
- ;---|*|----====< MV101_ISR >====----
- ;---|*|
- ;---|*| ISR service routine for the MV101 MIDI interrupts.
- ;---|*|
- ; \*/
- ;
- MV101_ISR proc far
- push ds
- push ax
- push bx
- push cx
- push dx
-
- mov ax,@data
- mov ds,ax
- ;
- ; first time in, check for a MIDI interrupt
- ;
- mov dx,INTRCTLRST
- xor dx,[_MVTranslateCode] ; translate the address
-
- in al,dx ; get the interrupt status
- test al,bISmidi ; is this our interrupt?
- jnz mv_is_midi_int ; yes, go process it...
-
- test al,fISints ; are any of these interrupt legit?
- jjz midiint_done ; no, flush this int.
- ;
- ; this was not our interrupt, chain on...
- ;
- pop dx
- pop cx
- pop bx
- pop ax
- pop ds
- jmp dword ptr cs:[OldISR] ; pass off to the other code.
- ;
- mv_is_midi_int:
- ;
- ; check the receiver for data, or errors
- ;
- mov dx,MIDISTATUS
- xor dx,[_MVTranslateCode] ; translate the address
- in al,dx
- mov ah,al ; save a copy for xmitter
-
- and al,bMSRframeerr+bMSRififoovr+bMSRofifoovr ; overrun or frame error?
- jz mvmidi_int ; nope
- out dx,al ; clear errors
-
- mov dx,MIDICONTROL
- xor dx,[_MVTranslateCode] ; translate the address
-
- in al,dx
- or al,bMCRrstfifoi+bMCRrstfifoo ; reset FIFO in ptr
- out dx,al
- and al,NOT(bMCRrstfifoi+bMCRrstfifoo)
- out dx,al
- ;
- mvmidi_int:
- ;
- ; get the status once again for the second chance loop
- ;
- mov dx,MIDISTATUS
- xor dx,[_MVTranslateCode] ; translate the address
- in al,dx
- ;
- ; Only process the interrupt process wanted by the user
- ;
- test [ProcessControl],INTINPUT ; interrupt driven input?
- jz checktrans ; no, go check for int driven xmit
-
- test al,bMSRififo ; any data in input FIFO?
- jz checktrans ; no, go check the transmitter
-
- .errnz MIDIFIFOS-MIDISTATUS-1
-
- inc dx ; move to the status register
-
- in al,dx
- mov cl,al
- and cx,bMFCififo ; get # of bytes in FIFO
- jnz @F
- mov cx,16
- ;
- @@:
- mov dx,MIDIDATA ; move to the data register
- xor dx,[_MVTranslateCode] ; translate the address
- mov bx,[lpiMIQueue] ; get the input queue pointer
- ;
- mvrxloop:
- ;
- ; read the data off the receiver
- ;
- in al,dx ; fetch the received byte
- ;
- ; MIDI spec requires transmitter send something every 300 msec
- ; Active Sense (FE) is the standard "nothing for you" byte
- ;
- test [_MidiInFilter],MF_ACTSENSE ; filter out active sense
- jz @F ; no, keep it...
- cmp al, 0FEh ; Active Sense?
- je rxCont ; ..ignore it
- ;
- @@:
- cmp [MIDIiQueueCnt],MAXQUEUE; is it full?
- jb @F ; no, save it
- inc [_overflow] ; yes, list it as an error
- jmp short mvrxloop
- ;
- @@:
- mov [bx],al
- inc bx
- inc [MIDIiQueueCnt] ; one more in...
- cmp bx,offset iCircularQueue+MAXQUEUE
- jb rxCont
- mov bx,offset iCircularQueue
- ;
- rxCont:
- loop mvrxloop ; do all bytes listed in the queue
- mov [lpiMIQueue],bx ; save the input queue pointer
- jmp second_check ; make sure FIFO is empty
- ;
- checktrans:
- ;
- ; If we are using interrupt driven output, load the FIFO now...
- ;
- test [ProcessControl],INTOUTPUT; interrupt driven output?
- jz second_check ; no, just exit out
-
- ; reset the interrupt now.
-
- mov dx,MIDISTATUS
- xor dx,[_MVTranslateCode] ; translate the address
- mov al,bMSRofifo ; any data in output FIFO?
- out dx,al
-
- ; check for any outgoing data
-
- cmp [MIDIoQueueCnt],0 ; any queued up data?
- jz second_check ; no, just exit out
-
- mov dx,MIDIFIFOS
- xor dx,[_MVTranslateCode] ; translate the address
-
- in al,dx
- and ax,bMFCofifo ; get # of outgoing bytes
- mov cl,4
- shr al,cl ; right hand justify the number
- xchg ax,cx
- cmp cl,1 ; down to 1 byte free?
- je second_check ; yes, can't load it
- ja @F ; we have 15 or less entries
- mov cx,16 ; 16 entires fit, but...
- ;
- @@:
- dec cx ; we only load 15...
- mov dx,MIDIDATA ; move to the data register
- xor dx,[_MVTranslateCode] ; translate the address
- mov bx,[lpoMOQueue] ; get the input queue pointer
- ;
- txLoop:
- mov al,[bx] ; pass the next byte
- out dx,al
-
- inc bx ; move the pointer
- cmp bx,offset oCircularQueue+MAXQUEUE
- jb @F
- mov bx,offset oCircularQueue; it wrapped...
- ;
- @@:
- dec [MIDIoQueueCnt] ; any queued up data?
- loopnz txLoop
- mov [lpoMOQueue],bx
- ;
- ; all done with input and output processing. Check for more interrupts
- ;
- second_check:
- ;
- ; in case we received more MIDI data during this routine, check again...
- ;
- mov dx,INTRCTLRST
- xor dx,[_MVTranslateCode] ; translate the address
-
- in al,dx ; get the interrupt status
- test al,bISmidi ; is the interrupt still active?
- jjnz mvmidi_int ; yes, go process it...
- ;
- midiint_done:
- mov al,EOI ; acknowledge the interrupt.
- cmp [_IRQNumb],7
- jbe @F
- out IRQ2ACKREG, al ; ack the 2nd IRQ controller
- ;
- @@:
- out IRQ1ACKREG, al ; ack the 1st IRQ controller
-
- cli ; just in case...
- ToggleMV101mask ; make sure the line stays active
- ;
- busy_exit:
- pop dx
- pop cx
- pop bx
- pop ax
- pop ds
- iret
-
- MV101_ISR endp
-
- ;
- ; /*\
- ;---|*|----====< Yamaha_ISR >====----
- ;---|*|
- ;---|*| ISR service routine for the Yamaha 3802 interrupts.
- ;---|*|
- ; \*/
- ;
- Yamaha_ISR proc far
- push ds ; minimal save
- push dx
- push ax
-
- mov ax, @data ; establish our DS
- mov ds, ax
-
- mov dx, INTRCTLRST
- in al, dx ; acknowledge interrupt
- test al, bICmidi ; our MIDI interrupt?
- jnz isourint ; yes, go do it...
-
- pushf
- call dword ptr cs:[OldISR] ; perform the old interrupt
- jmp WOOPS_exit
- ;
- isourint:
- ;
- ; we can now process all MIDI interrupts here
- ;
- push es
- push di
- cld ; fatal to assume
- ;
- ; We will only process interrupt generated input if ProcessControl says so.
- ;
- test [ProcessControl],INTINPUT ; Int input?
- jz emptyRX ; polled, check each h/w
- ;
- ; Check for Rx IRQ (means FIFO-Rx went non-empty) empty the FIFO
- ;
- mov dx, MDSYSSTAT ; IRQ Status
- in al, dx
- and al, RxIRQ ; FIFO-RX non-empty?
- jz emptyRX ; ..jump if not
-
- .errnz MDIRQCLR-MDSYSSTAT-1
-
- inc dx
- out dx,al ; flush it...
- ;
- ; get the input queue & load'er up!
- ;
- mov ax,ds
- mov es,ax
- mov di,lpiMIQueue ; get the input to the queue
- ;
- rxISR_05:
- mov al, 3 ; 3x
- mov dx, MDSYSCTLR
- out dx, al
-
- mov dx, MDGROUP4 ; 34 = FIFO-Rx status
- in al, dx
- test al, RxRDY ; RxRDY bit?
- jz rxISR_10 ; ..jump if FIFO empty
-
- mov dx, MDGROUP6 ; 36 = FIFO-Rx data
- in al, dx ; fetch datum
- ;
- ; Eliminate some overhead! The MIDI spec requires transmitter send something
- ; every 300 msec. Active Sense (FE) is the standard "nothing for you" byte
- ;
- test [_MidiInFilter],MF_ACTSENSE ; filter out active sense
- jz @F ; no, keep it...
- cmp al, ACTV_SENSE ; Active Sense?
- je rxISR_05 ; ..ignore it
- ;
- @@:
- cmp [MIDIiQueueCnt],MAXQUEUE; is it full?
- jb @F ; no, save it
- inc _overflow
- jmp short rxISR_05
- ;
- @@:
- stosb
- inc [MIDIiQueueCnt] ; one more in...
- cmp di,offset iCircularQueue+MAXQUEUE
- jb rxISR_05
- mov di,offset iCircularQueue
-
- jmp rxISR_05
- ;
- rxISR_10:
- mov [lpiMIQueue],di ; get the input to the queue
- ;
- emptyRX:
- ;
- ; Check for Transmitter Empyt IRQ here
- ;
- test [ProcessControl],INTOUTPUT ; Int output?
- jz endMIDIint ; no, exit out...
-
- mov dx, MDSYSSTAT ; IRQ Status
- in al, dx
- and al, TxIRQ ; FIFO-Tx became empty?
- jz endMIDIint ; ..jump if not
-
- .errnz MDIRQCLR-MDSYSSTAT-1
-
- inc dx
- out dx,al ; flush it...
- ;
- ; output any data till done.
- ;
- cmp [MIDIoQueueCnt],0 ; any data in the queue?
- jz endMIDIint ; ..jump if not
-
- mov di,lpoMOQueue ; get the pointer to the queue
- mov dx, MDSYSCTLR ; index to Xmitter
- mov al,5
- out dx,al
- ;
- ytxLoop:
- mov dx, MDGROUP4 ; 54 = FIFO-Tx status
- in al, dx
- test al, TxRDY ; TxRDY bit?
- jz ytxDone ; ..jump if FIFO full
-
- mov dx, MDGROUP6 ; 56 = FIFO-Tx data
- mov al, [di]
- out dx, al ; ship datum
-
- inc di ; move the pointer
- cmp di,offset oCircularQueue+MAXQUEUE
- jb @F
- mov di,offset oCircularQueue; it wrapped...
- ;
- @@:
- dec [MIDIoQueueCnt] ; any queued up data?
- jnz ytxLoop ; do as much as possible
- ;
- ytxDone:
- mov [lpoMOQueue],di ; save the ending pointer
- ;
- endMIDIint:
- ;
- ; all int handling is done now, so restore the state & exit home...
- ;
- pop di
- pop es
-
- mov al, [MDctrl]
- mov dx, MDSYSCTLR
- out dx, al ; restore incoming state
- ;
- WOOPS_reenter:
- ;
- ; flush the data ready IRQ
- ;
- mov al,EOI ; acknowledge at the system level
- cmp _IRQNumb,7
- jbe @F
- out IRQ2ACKREG, al ; ack the 2nd IRQ controller
- ;
- @@:
- out IRQ1ACKREG, al ; ack the 1st IRQ controller
-
- ToggleMV101mask ; make sure the MV101 can generate ints
- ;
- WOOPS_exit:
- pop ax
- pop dx
- pop ds
- iret
-
- Yamaha_ISR endp
-
- ; /*\
- ;---|*| end of MIDIA.ASM
- ; \*/
-
- end
-
-